/*

  layoutswitch - a simple utility that shells out to `setxkbmap` to quickly
  alternate between two or more predefined keyboard layouts.

  USAGE: layoutswitch
  Switches to your next X11 layout, or back to your previous one.

 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// number of layouts to be used:
#define NUM_LAYOUTS 2

// This array holds all our "desired" keyboard layouts to be cycled.
// You need, however, to initiate it with a #define directive because C
// will not accept a const statement (C++ apparently does)
char* layoutholder[NUM_LAYOUTS];

// this function queries `setxkbmap` and parses the value in there.
char *
getlayout()
{
    char* layout = malloc(3); // hard assumption that layouts are always two letters (reasonable *most* of the times)
    FILE *p;
    p = popen("setxkbmap -query | grep layout | cut -d ' ' -f 6", "r");
    if (p == NULL) {
        printf("Error: setxkbmap not found. Please install it in this system.\n"); 
        return "er";
    }
    else {
        int ch; // counter for chars being read...
        int i = 0; // counter for new chars!
        while ((ch = fgetc(p)) != EOF) {
            layout[i] = ch;
            i++;
        }
        pclose(p);
        // patch up the string with NULL before you leave:
        layout[2] = '\0';
        return layout;
    }
}

void
switchlayout(char* curlayout)
{
    FILE* p;
    char stmt[15] = "setxkbmap "; // "prepared statement" a-la SQl

    for (int i = 0; i < NUM_LAYOUTS; i++) {
        // if there's a match go to the next layout in the array
        if (strncmp(curlayout, layoutholder[i], 2) == 0) {

            // however, if it's the last element, switch to #1:
            if ((i + 1) == NUM_LAYOUTS) {
                printf("Switching to %s layout.\n", layoutholder[0]);
                strcat(stmt, layoutholder[0]);
                p = popen(stmt, "r");
                break;
            }
            else {
                printf("Switching to %s layout.\n", layoutholder[i+1]);
                strcat(stmt, layoutholder[i+1]);
                p = popen(stmt, "r");
                break;
            }
        }
    }
    pclose(p);
}

int
main(int argc, char* argv[])
{
    layoutholder[0] = "us";
    layoutholder[1] = "br";
    // add as many layoutN as you wish to cycle through. i.e.:
    // layoutholder[2] = "be";
    // However, if you do, make sure you change the NUM_LAYOUTS constant!


    char* layout = getlayout();
    if (strncmp(layout, "er", 2) == 0) {
        // not able to query value. Clean up and quit.
        printf("Unable to query keyboard value.\n");
        free(layout);
        return 1;
    }

    switchlayout(layout);
    free(layout); // NECESSARY. Avoid the leak!

    return 0;
}
